﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App1AppHandler;
using System.Data.SqlClient;
using System.IO;
using System.Xml;
using System.Net.Sockets;
using System.Reflection;
using Reborn_WorldServer;
using Reborn_WorldServer.App1AppHandler;

namespace Reborn_Server.App1AppHandler
{
    public class SkillManager
    {
        public Character MyCharacter;

        private List<SkillLevel> skillLevels = new List<SkillLevel>();

        private decimal Slashing_1H = 0;
        private decimal Slashing_2H = 0;
        private decimal Blunt_1H = 0;
        private decimal Blunt_2H = 0;
        private decimal Piercing_1H = 0;
        private decimal Piercing_2H = 0;
        private decimal Range = 0;
        private decimal Throwing = 0;
        private decimal Hand = 0;

        private decimal Fire = 0;
        private decimal Ice = 0;
        private decimal Holy = 0;
        private decimal Unholy = 0;
        private decimal Mentality = 0;
        private decimal Shadow = 0;
        private decimal Might = 0;
        private decimal Resilience = 0;

        private decimal Slashing_1H_Training = 0;
        private decimal Slashing_2H_Training = 0;
        private decimal Blunt_1H_Training = 0;
        private decimal Blunt_2H_Training = 0;
        private decimal Piercing_1H_Training = 0;
        private decimal Piercing_2H_Training = 0;
        private decimal Range_Training = 0;
        private decimal Throwing_Training = 0;
        private decimal Hand_Training = 0;

        private decimal Fire_Training = 0;
        private decimal Ice_Training = 0;
        private decimal Holy_Training = 0;
        private decimal Unholy_Training = 0;
        private decimal Mentality_Training = 0;
        private decimal Shadow_Training = 0;
        private decimal Might_Training = 0;
        private decimal Resilience_Training = 0;

        private decimal Level1Exp = 216;
        private decimal Multiplier = 1.3M;

        //Spell School Requirements
        //15    15 per      Have 1
        //50    25 per      Have 2
        //105    35 per      Have 3

        private int getRequiredSpellLevels(int knownSchools)
        {
            if (knownSchools == 0)
                return 0;

            int requiredLevels = 15;
            requiredLevels = requiredLevels + (10 * (knownSchools - 1));
            requiredLevels = requiredLevels * knownSchools;

            return requiredLevels;
        }
        public int getRequiredSpellLevelsForThisSchool()
        {
            return getRequiredSpellLevels(getTotalKnownSchools());
        }
        public int getRequiredSpellLevelsForNextSchool()
        {
            return getRequiredSpellLevels(getTotalKnownSchools() + 1);
        }
        public decimal getTotalSpellLevels()
        {
            decimal result = 0;

            if (Fire > -1) result = result + GetCurrentLevel(Fire);
            if (Ice > -1) result = result + GetCurrentLevel(Ice);
            if (Holy > -1) result = result + GetCurrentLevel(Holy);
            if (Unholy > -1) result = result + GetCurrentLevel(Unholy);
            if (Mentality > -1) result = result + GetCurrentLevel(Mentality);
            if (Shadow > -1) result = result + GetCurrentLevel(Shadow);
            if (Might > -1) result = result + GetCurrentLevel(Might);
            if (Resilience > -1) result = result + GetCurrentLevel(Resilience);

            return result;
        }
        public int getTotalKnownSchools()
        {
            int result = 0;

            if (Fire > -1) result++;
            if (Ice > -1) result++;
            if (Holy > -1) result++;
            if (Unholy > -1) result++;
            if (Mentality > -1) result++;
            if (Shadow > -1) result++;
            if (Might > -1) result++;
            if (Resilience > -1) result++;

            return result;
        }

        public void applyDeathPenalty(int percentOfPenalty)
        {
            decimal maxLevel = getMaxSkill();
            int currentLevel = System.Convert.ToInt32(Math.Floor(maxLevel));

            if (maxLevel < 10)
                return;

            bool isMagic = false;
            string maxSkillType = "";
            decimal skill = 0;
            if (Slashing_1H > skill)
            {
                skill = Slashing_1H;
                maxSkillType = "Slashing_1H";
            }
            if (Slashing_2H > skill)
            {
                skill = Slashing_2H;
                maxSkillType = "Slashing_2H";
            }
            if (Blunt_1H > skill) 
            {
                skill = Blunt_1H;
                maxSkillType = "Blunt_1H";
            }
            if (Blunt_2H > skill)
            {
                skill = Blunt_2H;
                maxSkillType = "Blunt_2H";
            }
            if (Piercing_1H > skill) 
            {
                skill = Piercing_1H;
                maxSkillType = "Piercing_1H";
            }
            if (Piercing_2H > skill) 
            {
                skill = Piercing_2H;
                maxSkillType = "Piercing_2H";
            }
            if (Range > skill) 
            {
                skill = Range;
                maxSkillType = "Range";
            }
            if (Throwing > skill) 
            {
                skill = Throwing;
                maxSkillType = "Throwing";
            }
            if (Hand > skill) 
            {
                skill = Hand;
                maxSkillType = "Hand";
            }

            if (Fire > skill)
            {
                skill = Fire;
                maxSkillType = "Fire";
                isMagic = true;
            }
            if (Ice > skill)
            {
                skill = Ice;
                maxSkillType = "Ice";
                isMagic = true;
            }
            if (Holy > skill)
            {
                skill = Holy;
                maxSkillType = "Holy";
                isMagic = true;
            }
            if (Unholy > skill)
            {
                skill = Unholy;
                maxSkillType = "Unholy";
                isMagic = true;
            }
            if (Mentality > skill)
            {
                skill = Mentality;
                maxSkillType = "Mentality";
                isMagic = true;
            }
            if (Shadow > skill)
            {
                skill = Shadow;
                maxSkillType = "Shadow";
                isMagic = true;
            }
            if (Might > skill)
            {
                skill = Might;
                maxSkillType = "Might";
                isMagic = true;
            }
            if (Resilience > skill)
            {
                skill = Resilience;
                maxSkillType = "Resilience";
                isMagic = true;
            }

            decimal penalty = 0;
            if (isMagic == false)
                penalty = 30;
            else
                penalty = 45;

            penalty = penalty * Math.Floor(maxLevel);
            penalty = penalty * System.Convert.ToDecimal((percentOfPenalty / 100.00));

            if (penalty != 0)
            {
                //Use Reflection
                FieldInfo fi = this.GetType().GetField(maxSkillType, BindingFlags.Instance | BindingFlags.NonPublic);
                decimal currentExp = System.Convert.ToDecimal(fi.GetValue(this));

                currentExp = currentExp - penalty;
                fi.SetValue(this, currentExp);

                updateSkill(maxSkillType);

                MyCharacter.SendMessage("You have fallen in " + maxSkillType + " skill!", "server");

                int newLevel = System.Convert.ToInt32(Math.Floor(GetCurrentLevel(maxSkillType)));
                if (newLevel != currentLevel)
                    MyCharacter.SendMessage("You have lost a skill level!", "server");
            }
        }

        public decimal getMaxSkill()
        {
            decimal maxLevel = 0;
            if (Slashing_1H > maxLevel) maxLevel = Slashing_1H;
            if (Slashing_2H > maxLevel) maxLevel = Slashing_2H;
            if (Blunt_1H > maxLevel) maxLevel = Blunt_1H;
            if (Blunt_2H > maxLevel) maxLevel = Blunt_2H;
            if (Piercing_1H > maxLevel) maxLevel = Piercing_1H;
            if (Piercing_2H > maxLevel) maxLevel = Piercing_2H;
            if (Range > maxLevel) maxLevel = Range;
            if (Throwing > maxLevel) maxLevel = Throwing;
            if (Hand > maxLevel) maxLevel = Hand;
            if (Fire > maxLevel) maxLevel = Fire;
            if (Ice > maxLevel) maxLevel = Ice;
            if (Holy > maxLevel) maxLevel = Holy;
            if (Unholy > maxLevel) maxLevel = Unholy;
            if (Mentality > maxLevel) maxLevel = Mentality;
            if (Shadow > maxLevel) maxLevel = Shadow;
            if (Might > maxLevel) maxLevel = Might;
            if (Resilience > maxLevel) maxLevel = Resilience;

            return GetCurrentLevel(maxLevel);
        }

        public void SetTrainingValue(string skillType, decimal value)
        {
            //Use reflection to set the variables above because its not as annoying as a huge switch to translate string parameter to variable
            FieldInfo fi = this.GetType().GetField(skillType + "_Training", BindingFlags.Instance | BindingFlags.NonPublic);
            fi.SetValue(this, value);
        }

        public decimal GetTraining(string skillType)
        {
            if (skillType == "Alchemy")
            {
                return 0;
            }
            else
            {
                //Use reflection
                FieldInfo fi = this.GetType().GetField(skillType + "_Training", BindingFlags.Instance | BindingFlags.NonPublic);
                return System.Convert.ToDecimal(fi.GetValue(this));
            }
        }

        public decimal GetTotalExp(string skillType)
        {
            //Use reflection
            FieldInfo fi = this.GetType().GetField(skillType, BindingFlags.Instance | BindingFlags.NonPublic);
            return System.Convert.ToDecimal(fi.GetValue(this));
        }

        public decimal GetTrainedToLevel(string skillType)
        {
            //Get current training
            decimal currentTraining = GetTraining(skillType);
            if (currentTraining == 0)
                return -1;

            decimal currentLevel = GetCurrentLevel(skillType);
            decimal nextLevel = Math.Floor(currentLevel) + 1;
            decimal levelDifference = nextLevel - currentLevel;

            //Stores the total training that we can have for current level (not counting what we already have)
            decimal totalTrainingForCurrentLevel = 0;

            //Calculate max possible training for current level.
            decimal total;
            decimal level;
            GetExpReq(currentLevel, out total, out level);

            //Get the amout of exp left to gain in our current level
            totalTrainingForCurrentLevel = levelDifference * System.Convert.ToInt32(Math.Floor(level));
            //Divide by 2 due to 2x exp with training.
            totalTrainingForCurrentLevel = totalTrainingForCurrentLevel / 2;
            //Multiply by level to get training cost
            totalTrainingForCurrentLevel = totalTrainingForCurrentLevel * System.Convert.ToInt32(Math.Floor(currentLevel));
            
            while (currentTraining > totalTrainingForCurrentLevel)
            {
                currentLevel = Math.Floor(currentLevel) + 1;
                currentTraining = currentTraining - totalTrainingForCurrentLevel;
                levelDifference = 1;

                GetExpReq(currentLevel, out total, out level);

                //Get the amout of exp left to gain in our current level
                totalTrainingForCurrentLevel = System.Convert.ToInt32(Math.Floor(level));
                //Divide by 2 due to 2x exp with training.
                totalTrainingForCurrentLevel = totalTrainingForCurrentLevel / 2;
                //Multiply by level to get training cost
                totalTrainingForCurrentLevel = totalTrainingForCurrentLevel * System.Convert.ToInt32(Math.Floor(currentLevel));
            }

            decimal result = currentLevel + ((currentTraining / totalTrainingForCurrentLevel) * levelDifference);

            result = Math.Round(result, 2);

            return result;
        }
        public int GetAvailableTraining(string skillType)
        {
            int availableTraining = 0;

            decimal CurrentLevel = GetCurrentLevel(skillType);
            decimal NextLevel = Math.Floor(CurrentLevel) + 1;

            decimal LevelDifference = NextLevel - CurrentLevel;

            //If we're past .50 skill our training will run into our next level
            if (LevelDifference < .5M)
            {
                //Calculate NEXT level.
                decimal nextTotal;
                decimal nextLevel;
                GetExpReq(NextLevel, out nextTotal, out nextLevel);

                //.5 - Level Difference gives us the level amout we can train into the next level -- Skill 1.80 = Level Diff .20   (.50 - .20 = .30)  .20 Level 1, .30 Level 2
                //Total Exp we can go into our next level.
                decimal availNext = (.5M - LevelDifference) * System.Convert.ToInt32(nextLevel);
                
                //Divide by 2 because training makes exp 2x - gets added WITH regular skill gain, so we have to take out whats going to get gained naturally
                availNext = availNext / 2;
                
                //Multiply result by level to get training cost
                availNext = availNext * System.Convert.ToInt32(Math.Floor(NextLevel));

                //Store result
                availableTraining = System.Convert.ToInt32(availNext);


                //Calculate CURRENT level.
                decimal total;
                decimal level;
                GetExpReq(CurrentLevel, out total, out level);

                //Get the amout of exp left to gain in our current level
                availNext = (LevelDifference) * System.Convert.ToInt32(Math.Floor(level));
                //Divide by 2 due to 2x exp with training.
                availNext = availNext / 2;
                //Multiply by level to get training cost
                availNext = availNext * System.Convert.ToInt32(Math.Floor(CurrentLevel));

                //Add to result from NEXT level
                availableTraining = availableTraining + System.Convert.ToInt32(availNext);
            }
            //We're below .50 training. Its all calculated based on CURRENT level.
            else
            {
                decimal total;
                decimal level;
                GetExpReq(CurrentLevel, out total, out level);

                //Get exp for .50 of current level
                availableTraining = System.Convert.ToInt32(.5M * level);

                //Divide by 2 since we will gain 2x exp with training
                availableTraining = availableTraining / 2;

                //Multiply by current level to get training cost.
                availableTraining = availableTraining * System.Convert.ToInt32(Math.Floor(CurrentLevel));
            }

            //Get current training
            decimal training = GetTraining(skillType);
            
            //Remove current training from available training.
            availableTraining = availableTraining - System.Convert.ToInt32(Math.Floor(training));

            return availableTraining;
        }

        //Gets the exp required for specified level Returns TOTAL exp (level plus all levels up to) and total exp required to level from prev to specified
        public void GetExpReq(decimal level, out decimal total, out decimal totalForLevel)
        {
            total = Level1Exp;
            totalForLevel = Level1Exp;

            for (int x = 2; x <= level; x++)
            {
                totalForLevel = totalForLevel * Multiplier;
                total = total + totalForLevel;
            }
        }

        public decimal GetCurrentLevel(string skillType)
        {
            if (skillType == "")
                return 0;

            decimal totalExp = 0;
            if (skillType == "Alchemy")
            {
                totalExp = getSkillLevelExp(skillType);
            }
            else
            {
                //Use reflection to get the value because its not as annoying as a huge switch
                //Returns global value above : private decimal SKILL
                FieldInfo fi = this.GetType().GetField(skillType, BindingFlags.Instance | BindingFlags.NonPublic);
                totalExp = System.Convert.ToDecimal(fi.GetValue(this));
            }

            decimal currentLevel = GetCurrentLevel(totalExp);
            return System.Convert.ToDecimal(Math.Round(currentLevel, 2));
        }

        private decimal getSkillLevelExp(string skillType)
        {
            lock (skillLevels)
            {
                foreach (SkillLevel skillLevel in skillLevels)
                {
                    if (skillLevel.Skill == skillType)
                        return skillLevel.Exp;
                }
            }

            return -1;
        }

        private List<SkillLevel> getDirtySkillLevels()
        {
            List<SkillLevel> dirtySkills = new List<SkillLevel>();
            lock (skillLevels)
            {
                foreach (SkillLevel skillLevel in skillLevels)
                {
                    if (skillLevel.isDirty == true)
                    {
                        skillLevel.isDirty = false;
                        dirtySkills.Add(skillLevel);
                    }
                }
            }

            return dirtySkills;
        }

        public void removeSkillLevel(string skillType)
        {
            lock (skillLevels)
            {
                foreach (SkillLevel skillLevel in skillLevels)
                {
                    if (skillLevel.Skill == skillType)
                    {
                        skillLevel.Exp = -1;
                        skillLevel.isDirty = true;
                        break;
                    }
                }
            }
            updateSkill(skillType, true);
        }

        private decimal addSkillLevelExp(string skillType, decimal value)
        {
            lock (skillLevels)
            {
                foreach (SkillLevel skillLevel in skillLevels)
                {
                    if (skillLevel.Skill == skillType)
                    {
                        skillLevel.Exp = skillLevel.Exp + value;
                        skillLevel.isDirty = true;
                        return skillLevel.Exp;
                    }
                }

                SkillLevel sl = new SkillLevel();
                sl.IsTraining = false;
                sl.Skill = skillType;
                sl.Type = getSkillDBType(skillType);
                sl.Exp = 0;
                sl.isDirty = true;

                skillLevels.Add(sl);

                return value;
            }
        }

        private string getSkillDBType(string skill)
        {
            if (skill == "Alchemy")
                return "Trade";

            if (skill == "Slashing_1H" || skill == "Slashing_2H" || skill == "Range" || skill == "Hand" ||
                skill == "Piercing_1H" || skill == "Piercing_2H" || skill == "Blunt_1H" || skill == "Blunt_2")
            {
                return "Melee";
            }

            return "Magic";
        }

        public decimal GetCurrentLevel(decimal totalExp)
        {
            if (totalExp == -1)
                return 0;

            if (totalExp == 0)
                return 1;

            decimal currentLevel = 1;

            decimal neededForNext = Level1Exp;
            decimal neededForLast = 0;

            decimal ctr = 1;
            while (neededForNext < totalExp)
            {
                neededForLast = neededForNext;

                ctr++;
                decimal total;
                decimal totalFor;
                GetExpReq(ctr,out total, out totalFor);

                neededForNext = total;
            }

            decimal totalForLevel = neededForNext - neededForLast;
            decimal totalIntoLevel = totalExp - neededForLast;

            decimal percentInto = totalIntoLevel / totalForLevel;

            currentLevel = (ctr) + percentInto;

            return System.Convert.ToDecimal(Math.Round(currentLevel, 2));
        }

        public void AddTraining(string skillType, int amount)
        {
            FieldInfo fi = this.GetType().GetField(skillType + "_Training", BindingFlags.Instance | BindingFlags.NonPublic);
            decimal training = GetTraining(skillType);
            training = training + amount;
            fi.SetValue(this, training);
        }

        public SkillManager(Character character)
        {
            MyCharacter = character;

            //LOAD ITEM IDs
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Characters_Skills_Select", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@CharacterID", character.ID);

            MyCon.Open();
            SqlDataReader SDR = SQLCom.ExecuteReader();

            while (SDR.Read())
            {
                Slashing_1H = decimal.Parse(SDR["Slashing_1H"].ToString());
                Slashing_2H = decimal.Parse(SDR["Slashing_2H"].ToString());
                Blunt_1H = decimal.Parse(SDR["Blunt_1H"].ToString());
                Blunt_2H = decimal.Parse(SDR["Blunt_2H"].ToString());
                Piercing_1H = decimal.Parse(SDR["Piercing_1H"].ToString());
                Piercing_2H = decimal.Parse(SDR["Piercing_2H"].ToString());
                Range = decimal.Parse(SDR["Range"].ToString());
                Throwing = decimal.Parse(SDR["Throwing"].ToString());
                Hand = decimal.Parse(SDR["Hand"].ToString());

                Fire = decimal.Parse(SDR["Fire"].ToString());
                Ice = decimal.Parse(SDR["Ice"].ToString()); 
                Holy = decimal.Parse(SDR["Holy"].ToString()); 
                Unholy = decimal.Parse(SDR["Unholy"].ToString()); 
                Mentality = decimal.Parse(SDR["Mentality"].ToString()); 
                Shadow = decimal.Parse(SDR["Shadow"].ToString()); 
                Might = decimal.Parse(SDR["Might"].ToString()); 
                Resilience = decimal.Parse(SDR["Resilience"].ToString()); 

                Slashing_1H_Training = int.Parse(SDR["Slashing_1H_Training"].ToString());
                Slashing_2H_Training = int.Parse(SDR["Slashing_2H_Training"].ToString());
                Blunt_1H_Training = int.Parse(SDR["Blunt_1H_Training"].ToString());
                Blunt_2H_Training = int.Parse(SDR["Blunt_2H_Training"].ToString());
                Piercing_1H_Training = int.Parse(SDR["Piercing_1H_Training"].ToString());
                Piercing_2H_Training = int.Parse(SDR["Piercing_2H_Training"].ToString());
                Range_Training = int.Parse(SDR["Range_Training"].ToString());
                Throwing_Training = int.Parse(SDR["Throwing_Training"].ToString());
                Hand_Training = decimal.Parse(SDR["Hand_Training"].ToString());

                Fire_Training = int.Parse(SDR["Fire_Training"].ToString());
                Ice_Training = int.Parse(SDR["Ice_Training"].ToString());
                Holy_Training = int.Parse(SDR["Holy_Training"].ToString());
                Unholy_Training = int.Parse(SDR["Unholy_Training"].ToString());
                Mentality_Training = int.Parse(SDR["Mentality_Training"].ToString());
                Shadow_Training = int.Parse(SDR["Shadow_Training"].ToString());
                Might_Training = int.Parse(SDR["Might_Training"].ToString());
                Resilience_Training = int.Parse(SDR["Resilience_Training"].ToString()); 
            }

            SDR.Close();

            SQLCom = new SqlCommand("Characters_Levels_Select", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@CharacterID", character.ID);

            SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                SkillLevel skillLevel = new SkillLevel();
                skillLevel.Exp = decimal.Parse(SDR["Exp"].ToString());
                skillLevel.IsTraining = bool.Parse(SDR["IsTraining"].ToString());
                skillLevel.Skill = SDR["Skill"].ToString();
                skillLevel.Type = SDR["Type"].ToString();

                skillLevels.Add(skillLevel);

                if (skillLevel.Exp != -1)
                    updateSkill(skillLevel.Skill);
            }

            SDR.Dispose();
            MyCon.Close();
            MyCon.Dispose();

            if (Slashing_1H != 0)
                updateSkill("Slashing_1H");
            if (Slashing_2H != 0)
                updateSkill("Slashing_2H");
            if (Blunt_1H != 0)
                updateSkill("Blunt_1H");
            if (Blunt_2H != 0)
                updateSkill("Blunt_2H");
            if (Piercing_1H != 0)
                updateSkill("Piercing_1H");
            if (Piercing_2H != 0)
                updateSkill("Piercing_2H");
            if (Range != 0)
                updateSkill("Range");
            if (Throwing != 0)
                updateSkill("Throwing");
            if (Hand != 0)
                updateSkill("Hand");

            if (Fire > -1)
                updateSkill("Fire");
            if (Ice > -1)
                updateSkill("Ice");
            if (Holy > -1)
                updateSkill("Holy");
            if (Unholy > -1)
                updateSkill("Unholy");
            if (Mentality > -1)
                updateSkill("Mentality");
            if (Shadow > -1)
                updateSkill("Shadow");
            if (Might > -1)
                updateSkill("Might");
            if (Resilience > -1)
                updateSkill("Resilience");
        }


        private void saveSkillLevels()
        {
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            MyCon.Open();
            SqlTransaction MyTrans = MyCon.BeginTransaction();

            SqlCommand SQLCom = new SqlCommand();
            SQLCom.Connection = MyCon;
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Transaction = MyTrans;

            List<SkillLevel> dirtySkills = getDirtySkillLevels();

            try
            {
                SQLCom.CommandText = "Characters_Levels_Update";
                SQLCom.Parameters.AddWithValue("@CharacterID", MyCharacter.ID);

                SQLCom.Parameters.Add("@Skill", System.Data.SqlDbType.VarChar);
                SQLCom.Parameters.Add("@Exp", System.Data.SqlDbType.Decimal);
                SQLCom.Parameters.Add("@IsTraining", System.Data.SqlDbType.Bit);
                SQLCom.Parameters.Add("@Type", System.Data.SqlDbType.VarChar);

                foreach (SkillLevel skillLevel in dirtySkills)
                {
                    SQLCom.Parameters["@Skill"].Value = skillLevel.Skill;
                    SQLCom.Parameters["@Exp"].Value = skillLevel.Exp;
                    SQLCom.Parameters["@IsTraining"].Value = skillLevel.IsTraining;
                    SQLCom.Parameters["@Type"].Value = skillLevel.Type;

                    SQLCom.ExecuteNonQuery();
                }

                MyTrans.Commit();
            }
            catch
            {
                MyTrans.Rollback();

                foreach (SkillLevel skillLevel in dirtySkills)
                    skillLevel.isDirty = true;
            }
            finally
            {
                MyCon.Close();
                MyCon.Dispose();
            }
        }
        public void SaveSkills()
        {
            saveSkillLevels();

            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Characters_Skills_Update", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@CharacterID", MyCharacter.ID);

            SQLCom.Parameters.AddWithValue("@Slashing_1H", Slashing_1H);
            SQLCom.Parameters.AddWithValue("@Slashing_2H", Slashing_2H);
            SQLCom.Parameters.AddWithValue("@Blunt_1H", Blunt_1H);
            SQLCom.Parameters.AddWithValue("@Blunt_2H", Blunt_2H);
            SQLCom.Parameters.AddWithValue("@Piercing_1H", Piercing_1H);
            SQLCom.Parameters.AddWithValue("@Piercing_2H", Piercing_2H);
            SQLCom.Parameters.AddWithValue("@Range", Range);
            SQLCom.Parameters.AddWithValue("@Throwing", Throwing);
            SQLCom.Parameters.AddWithValue("@Hand", Hand);

            SQLCom.Parameters.AddWithValue("@Fire", Fire);
            SQLCom.Parameters.AddWithValue("@Ice", Ice);
            SQLCom.Parameters.AddWithValue("@Holy", Holy);
            SQLCom.Parameters.AddWithValue("@Unholy", Unholy);
            SQLCom.Parameters.AddWithValue("@Mentality", Mentality);
            SQLCom.Parameters.AddWithValue("@Shadow", Shadow);
            SQLCom.Parameters.AddWithValue("@Might", Might);
            SQLCom.Parameters.AddWithValue("@Resilience", Resilience);

            SQLCom.Parameters.AddWithValue("@Slashing_1H_Training", System.Convert.ToInt32(Math.Floor(Slashing_1H_Training)));
            SQLCom.Parameters.AddWithValue("@Slashing_2H_Training", System.Convert.ToInt32(Math.Floor(Slashing_2H_Training)));
            SQLCom.Parameters.AddWithValue("@Blunt_1H_Training", System.Convert.ToInt32(Math.Floor(Blunt_1H_Training)));
            SQLCom.Parameters.AddWithValue("@Blunt_2H_Training", System.Convert.ToInt32(Math.Floor(Blunt_2H_Training)));
            SQLCom.Parameters.AddWithValue("@Piercing_1H_Training", System.Convert.ToInt32(Math.Floor(Piercing_1H_Training)));
            SQLCom.Parameters.AddWithValue("@Piercing_2H_Training", System.Convert.ToInt32(Math.Floor(Piercing_2H_Training)));
            SQLCom.Parameters.AddWithValue("@Range_Training", System.Convert.ToInt32(Math.Floor(Range_Training)));
            SQLCom.Parameters.AddWithValue("@Throwing_Training", System.Convert.ToInt32(Math.Floor(Throwing_Training)));
            SQLCom.Parameters.AddWithValue("@Hand_Training", System.Convert.ToInt32(Math.Floor(Hand_Training)));

            SQLCom.Parameters.AddWithValue("@Fire_Training", System.Convert.ToInt32(Math.Floor(Fire_Training)));
            SQLCom.Parameters.AddWithValue("@Ice_Training", System.Convert.ToInt32(Math.Floor(Ice_Training)));
            SQLCom.Parameters.AddWithValue("@Holy_Training", System.Convert.ToInt32(Math.Floor(Holy_Training)));
            SQLCom.Parameters.AddWithValue("@Unholy_Training", System.Convert.ToInt32(Math.Floor(Unholy_Training)));
            SQLCom.Parameters.AddWithValue("@Mentality_Training", System.Convert.ToInt32(Math.Floor(Mentality_Training)));
            SQLCom.Parameters.AddWithValue("@Shadow_Training", System.Convert.ToInt32(Math.Floor(Shadow_Training)));
            SQLCom.Parameters.AddWithValue("@Might_Training", System.Convert.ToInt32(Math.Floor(Might_Training)));
            SQLCom.Parameters.AddWithValue("@Resilience_Training", System.Convert.ToInt32(Math.Floor(Resilience_Training)));

            MyCon.Open();
            SQLCom.ExecuteNonQuery();
            MyCon.Close();
            MyCon.Dispose();
        }

        public void SetSkill(string type, decimal level)
        {
            Loot leftHand = MyCharacter.LeftHand;
            if (leftHand != null)
                MyCharacter.LeftHand = null;

            Loot rightHand = MyCharacter.RightHand;
            if (rightHand != null)
                MyCharacter.RightHand = null;

            decimal total;
            decimal totalForLevel;
            GetExpReq(level - 1, out total, out totalForLevel);

            decimal intoNext = level - Math.Floor(level);
            if (intoNext != 0)
            {
                decimal totalNext;
                decimal totalForLevelNext;
                GetExpReq(level, out totalNext, out totalForLevelNext);

                total = total + (totalForLevelNext * intoNext);
            }

            //Use Reflection
            FieldInfo fi = this.GetType().GetField(type, BindingFlags.Instance | BindingFlags.NonPublic);
            if (fi != null)
                fi.SetValue(this, total);

            updateSkill(type);

            if (leftHand != null)
                MyCharacter.LeftHand = leftHand;
            if (rightHand != null)
                MyCharacter.RightHand = rightHand;

            MyCharacter.Update_Character();
        }

        public void AddExp(string type, decimal exp)
        {
            decimal levelBefore = GetCurrentLevel(type);
            decimal levelAfter = 0;

            decimal training = GetTraining(type);
            if (training > 0)
            {
                //We do not have enough training to double the exp
                if (training < exp * Math.Floor(levelBefore))
                {
                    exp = exp + (training / levelBefore);
                    SetTrainingValue(type, 0);
                }
                //We DO have enough training to double the exp
                else
                {
                    decimal trainingToUse = exp * Math.Floor(levelBefore);
                    exp = exp * 2;
                    SetTrainingValue(type, training - trainingToUse);
                }
            }

            bool LeftHandMeetsReq = true;
            if (MyCharacter.LeftHand != null && MyCharacter.LeftHand is Equipment && MyCharacter.equipManager.MeetsRequirements((Equipment)MyCharacter.LeftHand) == false)
                LeftHandMeetsReq = false;
            bool RightHandMeetsReq = true;
            if (MyCharacter.RightHand != null && MyCharacter.RightHand is Equipment && MyCharacter.equipManager.MeetsRequirements((Equipment)MyCharacter.RightHand) == false)
                RightHandMeetsReq = false;

            if (type == "Alchemy")
            {
                decimal currentExp = addSkillLevelExp(type, exp);
            }
            else
            {
                //Use Reflection
                FieldInfo fi = this.GetType().GetField(type, BindingFlags.Instance | BindingFlags.NonPublic);
                decimal currentExp = System.Convert.ToDecimal(fi.GetValue(this));
                currentExp = currentExp + exp;
                fi.SetValue(this, currentExp);
            }

            levelAfter = Math.Round(GetCurrentLevel(type), 2);

            if (Math.Floor(levelAfter) > Math.Floor(levelBefore))
            {
                bool updateCharacter = false;

                //Re-set the weapons if we meet requirements after the level up
                if (LeftHandMeetsReq == false)
                {
                    if (MyCharacter.LeftHand != null && MyCharacter.LeftHand is Equipment && MyCharacter.equipManager.MeetsRequirements((Equipment)MyCharacter.LeftHand) == true)
                    {
                        updateCharacter = true;
                        MyCharacter.LeftHand = MyCharacter.LeftHand;
                    }
                }
                if (RightHandMeetsReq == false)
                {
                    if (MyCharacter.RightHand != null && MyCharacter.RightHand is Equipment && MyCharacter.equipManager.MeetsRequirements((Equipment)MyCharacter.RightHand) == true)
                    {
                        updateCharacter = true;
                        MyCharacter.RightHand = MyCharacter.RightHand;
                    }
                }

                if (updateCharacter)
                    MyCharacter.Update_Character();

                Message message = new Message();
                message.Type = "server";
                message.CreatureID = MyCharacter.CreatureID;
                message.Text = "Server: You have reached level " + Math.Floor(levelAfter).ToString() + " in " + type + " Skill!";
                MyCharacter.AddMessage(message);
                MyCharacter.PlaySound("SkillUp", MyCharacter.MapX, MyCharacter.MapY);
            }
            if (levelBefore != levelAfter)
            {
                updateSkill(type);
            }
        }

        public int AdjustForCombat(string skillType, int seed, int statBonus)
        {
            int skillLevel = System.Convert.ToInt32(Math.Floor(GetCurrentLevel(skillType)));

            return SkillManager.AdjustForCombat(skillLevel, seed, statBonus);
        }

        static public int AdjustForCombat(int skillLevel, int seed, int statBonus)
        {
            return SkillManager.AdjustForCombat(skillLevel, seed, statBonus, 1);
        }
        static public int AdjustForCombat(int skillLevel, int seed, int statBonus, decimal divideSkillBonusBy)
        {
            if (skillLevel == 0 && seed == 0)
                return 0;

            int rawSkillBonus = 0;
            int percentToAdd = 0;

            for (int x = 2; x <= skillLevel; x++)
            {
                rawSkillBonus = rawSkillBonus + x - 1;
                percentToAdd = percentToAdd + 1;
            }

            rawSkillBonus = System.Convert.ToInt32(Math.Floor(rawSkillBonus / 2.00));

            rawSkillBonus = System.Convert.ToInt32(Math.Floor(rawSkillBonus / divideSkillBonusBy)); 

            seed = System.Convert.ToInt32(Math.Floor(seed * (1 + (percentToAdd / 100.00))));

            return seed + rawSkillBonus + statBonus;
        }
        public void updateSkill(string type)
        {
            updateSkill(type, false);
        }
        public void updateSkill(string type, bool remove)
        {
            string result = "";
            decimal level = GetCurrentLevel(type); 

            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

            xmldoc.WriteStartElement("skilldata");
            xmldoc.WriteAttributeString("Skill", type);

            if (remove == false)
                xmldoc.WriteAttributeString("Level", level.ToString());
            else
                xmldoc.WriteAttributeString("Level", "-1");

            xmldoc.WriteEndElement();

            xmldoc.Flush();

            xmldoc.Close();

            stringWriter.Flush();

            result = stringWriter.ToString();

            try
            {
                MyCharacter.ClientSocket.socket.BeginSend(result);
            }
            catch { }
        }
    }
    
}
